package com.bkjk.platform.druiddemo;

import com.bkjk.platform.druiddemo.aop.AopAspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.aop.aspectj.*;
import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator;
import org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;

/**
 * @author <a href="juntao.zhang@bkjk.com">juntao.zhang</a>
 * @Description:  利用spring xml得到 aspectj的实现。
 * @Package com.bkjk.platform.druiddemo
 * @date 2018/3/13 14:33
 * @see  AspectJAwareAdvisorAutoProxyCreator
 *
 *      生成 bean的代理{@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation(java.lang.Class, java.lang.String)}
 */
@Configuration
public class AspectConfiguration implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    private static final String ASPECT_BEAN_NAME = "aopAspect";

    private static final String EXPRESSION = "execution(* com.bkjk.platform.druiddemo.service.impl.UserManagerServiceImpl..*(..))";


    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Bean
    public AopAspect aopAspect() {
        AopAspect aopAspect = new AopAspect();
        return aopAspect;
    }

    @Bean
    public AspectJExpressionPointcut aspectJExpressionPointcut() {
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression(EXPRESSION);
        return aspectJExpressionPointcut;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    @Bean
    public AspectJPointcutAdvisor aspectJAfterThrowingAdvice(AspectJExpressionPointcut aspectJExpressionPointcut,AspectInstanceFactory aspectInstanceFactory,AopAspect aopAspect) throws NoSuchMethodException {
        Method doAfterThrowing = AopAspect.class.getDeclaredMethod("doAfterThrowing", JoinPoint.class, Throwable.class);
        AspectJAfterThrowingAdvice aspectJAfterThrowingAdvice = new AspectJAfterThrowingAdvice(doAfterThrowing,aspectJExpressionPointcut,aspectInstanceFactory);
        aspectJAfterThrowingAdvice.setAspectName(ASPECT_BEAN_NAME);
        AspectJPointcutAdvisor aspectJPointcutAdvisor = new AspectJPointcutAdvisor(aspectJAfterThrowingAdvice);
       return aspectJPointcutAdvisor;
    }


    @Bean
    public AspectJPointcutAdvisor aspectJAfterAdvice(AspectJExpressionPointcut aspectJExpressionPointcut,AspectInstanceFactory aspectInstanceFactory,AopAspect aopAspect) throws NoSuchMethodException {
        Method doAfterThrowing = AopAspect.class.getDeclaredMethod("doAfter", JoinPoint.class);
        AspectJAfterAdvice aspectJAfterAdvice = new AspectJAfterAdvice(doAfterThrowing,aspectJExpressionPointcut,aspectInstanceFactory);
        aspectJAfterAdvice.setAspectName(ASPECT_BEAN_NAME);
        AspectJPointcutAdvisor aspectJPointcutAdvisor = new AspectJPointcutAdvisor(aspectJAfterAdvice);
        return aspectJPointcutAdvisor;
    }


    @Bean
    public AspectJPointcutAdvisor aspectJAroundAdvice(AspectJExpressionPointcut aspectJExpressionPointcut,AspectInstanceFactory aspectInstanceFactory,AopAspect aopAspect) throws NoSuchMethodException {
        Method doAround = AopAspect.class.getDeclaredMethod("doAround", ProceedingJoinPoint.class);
        AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice(doAround,aspectJExpressionPointcut,aspectInstanceFactory);
        aspectJAroundAdvice.setAspectName(ASPECT_BEAN_NAME);
        AspectJPointcutAdvisor aspectJPointcutAdvisor = new AspectJPointcutAdvisor(aspectJAroundAdvice);
        return aspectJPointcutAdvisor;
    }

    @Bean
    public AspectInstanceFactory aspectInstanceFactory(AopAspect aopAspect) {
        SimpleBeanFactoryAwareAspectInstanceFactory simpleBeanFactoryAwareAspectInstanceFactory = new SimpleBeanFactoryAwareAspectInstanceFactory();
        simpleBeanFactoryAwareAspectInstanceFactory.setAspectBeanName(ASPECT_BEAN_NAME);
        simpleBeanFactoryAwareAspectInstanceFactory.setBeanFactory(applicationContext.getAutowireCapableBeanFactory());
        return simpleBeanFactoryAwareAspectInstanceFactory;
    }

}
